package com.berchen.hash;

import java.util.SortedMap;
import java.util.TreeMap;

/**
 * 带虚拟节点的一致性Hash算法
 */
public class ConsistencyHashVirtual {
    public static void main(String[] args){

        // 1 初始化  将服务器节点IP的Hash值对应到Hash环上。
        // 定义服务器IP
        String[] servers={"10.78.12.3","85.25.63.1","126.12.3.81","123.98.26.3"};

        // 可以排序的Map
        SortedMap<Integer,String> serverNode=new TreeMap<>();

        // 定义针对每个真实服务器虚拟出来的几个节点
        int virtaulCount=3;

        for(String server :servers){

            // 求出每一个Ip的Hash 值，对应到Hash环上 ,存储Hash值与IP的对应关系
            int serverHash=Math.abs(server.hashCode());
            serverNode.put(serverHash,server);

            // 处理虚拟节点
            for(int i =0;i<virtaulCount;i++){
                serverHash=Math.abs((server+"#"+i).hashCode());
                serverNode.put(serverHash,"虚拟"+i+"->"+server);
            }
        }
        // 2 针对客户端IP 求出Hash值
        String[] clients={"125.124.62.1","15.26.31.35","157.25.36.1"};
        for(String client:clients){
            int clientHash=Math.abs(client.hashCode());
            // 根据客户端IP的Hash值，找出哪一个服务器节点能够处理
            // 3 针对客户端找到能够处理当前客户端请求的服务器（哈希环上顺时针最近的服务器节点）；
            // tailMap 方法的作用是将找出比参数大的key 作为一个结合返回
            // 我们根据返回的集合是否有值：有 取第一个  ，没有 取整个map 的第一个元素
            SortedMap<Integer, String> integerStringSortedMap = serverNode.tailMap(clientHash);
            if(integerStringSortedMap.isEmpty()){
                // 取出整个第一个元素
                Integer firstKey = serverNode.firstKey();
                System.out.println("==========>>>>客户端："+client+" 被路由到服务器："+serverNode.get(firstKey));
            }
            else {
                Integer firstKey = integerStringSortedMap.firstKey();
                System.out.println("==========>>>>客户端："+client+" 被路由到服务器："+serverNode.get(firstKey));
            }
        }

    }
}
